package edu.stanford.bmir.protege.web.server.stkosutil.enricher;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Set;

import org.semanticweb.owlapi.model.EntityType;
import org.semanticweb.owlapi.model.OWLClass;
import org.semanticweb.owlapi.vocab.OWLRDFVocabulary;

import edu.stanford.bmir.protege.web.client.rpc.stkosutil.common.MatchLevel;
import edu.stanford.bmir.protege.web.client.rpc.stkosutil.common.UtilEntityType;
import edu.stanford.bmir.protege.web.client.rpc.stkosutil.enricher.CandidateEntity;
import edu.stanford.bmir.protege.web.server.owlapi.AssertedClassHierarchyProvider;
import edu.stanford.bmir.protege.web.server.owlapi.OWLAPIProject;
import edu.stanford.bmir.protege.web.server.owlapi.RenderingManager;
import edu.stanford.bmir.protege.web.server.stkosutil.mapper.OwlClassHolder;
import edu.stanford.bmir.protege.web.server.stkosutil.mapper.OwlClassHolderComparator;

public class RefOntology {
	private MatchLevel _matchLevel = MatchLevel.CASE_INSENSITIVE;
	private List<OwlClassHolder> _classHolderList = null;
	private OWLAPIProject _project = null;
	public RefOntology(OWLAPIProject project, MatchLevel matchLevel){
		_project = project;
		_matchLevel = matchLevel;
	}
	public void loadAllClasses() {
        List<OwlClassHolder> result = new ArrayList<OwlClassHolder>();
        RenderingManager rm = _project.getRenderingManager();
        Set<OWLClass> sClasses = _project.getRootOntology().getClassesInSignature();
        //boolean checkForDeprecated = project.getRootOntology().containsAnnotationPropertyInSignature(OWLRDFVocabulary.OWL_DEPRECATED.getIRI());
        for (OWLClass subclass : sClasses) {
        	if (subclass.getIRI().equals(OWLRDFVocabulary.OWL_THING.getIRI())){
        		continue;
        	}
            String browserText = rm.getBrowserText(subclass);
            String name = subclass.getIRI().toString();
            OwlClassHolder classHolder = new OwlClassHolder();;
            classHolder.setBrowserText(browserText);
            classHolder.setName(name);
            classHolder.setOwlClass(subclass);
            result.add(classHolder);
        }
        OwlClassHolderComparator comparator = new OwlClassHolderComparator(_matchLevel);
        Collections.sort(result, comparator);
        _classHolderList = result;
    }
	private ArrayList<OwlClassHolder> fetchMatchedClassHolders(String browserText){
		ArrayList<OwlClassHolder> matchedClassList = new ArrayList<OwlClassHolder>();
		OwlClassHolder seed = new OwlClassHolder();
		OwlClassHolderComparator comparator = new OwlClassHolderComparator(_matchLevel);
		seed.setBrowserText(browserText);
		int pos = Collections.binarySearch(_classHolderList, seed, comparator);
		if (pos<0){
			return matchedClassList;
		}
		
		matchedClassList.add(_classHolderList.get(pos));
		for (int i=pos+1; i<_classHolderList.size(); i++){
			if (comparator.compare(seed, _classHolderList.get(i))==0){  
				matchedClassList.add(_classHolderList.get(i));
			}else{
				break;
			}
		}
		for (int i=pos-1; i>=0; i--){
			if (comparator.compare(seed, _classHolderList.get(i))==0){
				matchedClassList.add(_classHolderList.get(i));
			}else{
				break;
			}
		}
		return matchedClassList;
	}
	public ArrayList<CandidateEntity> fetchCandidateChildClasses(String browserText){
		
		ArrayList<OwlClassHolder> matchedClassHolders = this.fetchMatchedClassHolders(browserText);
		if (matchedClassHolders==null || matchedClassHolders.size()==0){
			return null;
		}
		HashMap<String, CandidateEntity> sResult = new HashMap<String, CandidateEntity>();
		for (OwlClassHolder matchedClassHolder: matchedClassHolders){
			List<OwlClassHolder> subclassHolders = this.getSubclasses(_project, matchedClassHolder.getName());
			for (OwlClassHolder subclassHolder: subclassHolders){
				CandidateEntity candidateEntity = this.owlClassHolder2CandidateEntity(subclassHolder);
				sResult.put(candidateEntity.getBrowserText(), candidateEntity);
			}
		}
		Collection<CandidateEntity> cResult = sResult.values();
		ArrayList<CandidateEntity> result = new ArrayList<CandidateEntity>();
		for (CandidateEntity candidateEntity: cResult){
			result.add(candidateEntity);
		}
		return result;
		
	}
	private CandidateEntity owlClassHolder2CandidateEntity(OwlClassHolder classHolder){
		CandidateEntity candidatEntity = new CandidateEntity();
		candidatEntity.setBrowserText(classHolder.getBrowserText());
		candidatEntity.setEntityType(UtilEntityType.CLASS);
		candidatEntity.setSourceLabel(_project.getProjectId().toString());
		return candidatEntity;
	}
	
	private List<OwlClassHolder> getSubclasses(OWLAPIProject project, String className) {
	        if (className == null) {
	            return Collections.emptyList();
	        }
	        List<OwlClassHolder> result = new ArrayList<OwlClassHolder>();
	       
	        RenderingManager rm = project.getRenderingManager();
	        AssertedClassHierarchyProvider hierarchyProvider = project.getClassHierarchyProvider();
	        OWLClass cls = rm.getEntity(className, EntityType.CLASS);

	        boolean checkForDeprecated = project.getRootOntology().containsAnnotationPropertyInSignature(OWLRDFVocabulary.OWL_DEPRECATED.getIRI());
	        for (OWLClass subclass : new ArrayList<OWLClass>(hierarchyProvider.getChildren(cls))) {
	            boolean deprecated = false;
//	            if(checkForDeprecated) {
//	                deprecated = project.isDeprecated(subclass);
//	            }
	        //if (!deprecated) {
	              //  Set<OWLClass> children = hierarchyProvider.getChildren(subclass);
	              //  int subClassSubClassesCount = children.size();
	                String browserText = rm.getBrowserText(subclass);
	                String name = subclass.getIRI().toString();
	                OwlClassHolder classHolder = new OwlClassHolder();;
	                classHolder.setBrowserText(browserText);
	                classHolder.setName(name);
	                classHolder.setOwlClass(subclass);
	                //data.setDeprecated(deprecated);

	                //data.setValueType(ValueType.Cls);
	                result.add(classHolder);
//	            }
	        }
	        Collections.sort(result, new Comparator<OwlClassHolder>() {
	            public int compare(OwlClassHolder o1, OwlClassHolder o2) {
//	                if(o1.isDeprecated()) {
//	                    if(!o2.isDeprecated()) {
//	                        return 1;
//	                    }
//	                }
//	                else if(o2.isDeprecated()) {
//	                    return -1;
//	                }
	                String browserText1 = o1.getBrowserText();
	                String browserText2 = o2.getBrowserText();
	                if(browserText1.startsWith("'")) {
	                    browserText1 = browserText1.substring(1);
	                }
	                if(browserText2.startsWith("'")) {
	                    browserText2 = browserText2.substring(1);
	                }
	                return browserText1.compareToIgnoreCase(browserText2);
	            }
	        });
	        return result;
	    }
	
}

